package com.zn.asycn;

import com.zn.entity.KLineEntity;
import com.zn.entity.KLineTickDto;
import com.zn.util.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author YinJiaWei
 * @version 2018/12/2 11:48
 */
@Component
public class CalculateKLineExecutor {
    private static final Logger LOGGER = LoggerFactory.getLogger(CalculateKLineExecutor.class);
    public static ConcurrentHashMap<String,LinkedList<KLineTickDto>> ONE_MIN_KLINE=new ConcurrentHashMap<String,LinkedList<KLineTickDto>>();
    public static ConcurrentHashMap<String,LinkedHashMap<String,KLineTickDto>> FIVE_MIN_KLINE=new ConcurrentHashMap<String,LinkedHashMap<String,KLineTickDto>>();
    /**
     * 计算一分钟K线
     * @param hashKey 10001441-11:55
     * @param hashValue tick
     */
    public void calculateFiveMinKLine(String hashKey,KLineTickDto hashValue){
        try {
            String [] subHashKey=hashKey.split("-");
            String [] subHashKeyTime=subHashKey[1].split(":");
            Integer minute=Integer.valueOf(subHashKeyTime[1]);
            boolean flag=minute%5==0;
            /**是5的倍数**/
            if(flag){
                boolean hashKeyFalg=FIVE_MIN_KLINE.containsKey(hashKey);
                if(hashKeyFalg){
                    /**如果存在则继续往内存里放**/
                    LinkedHashMap<String,KLineTickDto> sonMap=FIVE_MIN_KLINE.get(hashKey);
                    sonMap.put(hashValue.getUpdateTime(),hashValue);
                    FIVE_MIN_KLINE.put(hashKey,sonMap);
                }else{
                    /**如果不存在
                     * 1、计算上一分钟的tick,并清空上一分钟的数据
                     * 2、开辟新的一分钟tick内存
                     */
                    Date beforeOneMinDate=DateUtils.addMinute(DateUtils.convertStringToDate("HH:mm", subHashKey[1]), -1);
                    String beforeOneMinStr=DateUtils.formatDate("HH:mm", beforeOneMinDate);
                    String beforeHashKey=subHashKey[0]+beforeOneMinStr;
                    Map<String,KLineTickDto> beforeOneMinMap=FIVE_MIN_KLINE.get(beforeHashKey);
                    if(beforeOneMinMap!=null){
                        List<KLineTickDto> values=(List<KLineTickDto>)beforeOneMinMap.values();
                        KLineEntity kLineEntity=new KLineEntity();
                        KLineTickDto headTick=values.get(0);
                        KLineTickDto tailTick=values.get(values.size()-1);
                        /**code**/
                        kLineEntity.setCode(subHashKey[0]);
                        /**开**/
                        kLineEntity.setOpen(Double.valueOf(headTick.getLastPrice()));
                        /**收**/
                        kLineEntity.setClose(Double.valueOf(tailTick.getLastPrice()));
                        /**成交量**/
                        Integer volum=Integer.valueOf(tailTick.getVolume())-Integer.valueOf(headTick.getVolume());
                        kLineEntity.setVolume(volum < 0 ? 0 : volum);
                        /**成交额**/
                        Double tradeAmt=Double.valueOf(tailTick.getTurnover())-Double.valueOf(headTick.getTurnover());
                        kLineEntity.setTradeAmt(tradeAmt<0?0:tradeAmt);
                        /**持仓量**/
                        Double positionNum=Double.valueOf(tailTick.getOpenInterest())-Double.valueOf(headTick.getOpenInterest());
                        kLineEntity.setPositionNum(positionNum<0?0:positionNum);
                        Double sumPrice=0.00;
                        for(KLineTickDto tick:values){
                            Double lastPrice=Double.valueOf(tick.getLastPrice());
                            /**高**/
                            if(kLineEntity.getHigh()==null || lastPrice>kLineEntity.getHigh()){
                                kLineEntity.setHigh(lastPrice);
                            }
                            /**低**/
                            if(kLineEntity.getLow()==null || lastPrice<kLineEntity.getLow()){
                                kLineEntity.setLow(lastPrice);
                            }
                            sumPrice+=lastPrice;
                        }
                        /**均价**/
                        Double avgPrice=new BigDecimal(sumPrice).divide(new BigDecimal(values.size())).doubleValue();
                        kLineEntity.setAvgPrc(avgPrice);
                        /**mongodb+8小时 时区问题**/
                        Date curTimeDates=DateUtils.addHour(DateUtils.convertStringToDate("yyyy-MM-dd HH:mm:ss", headTick.getUpdateTime()), 8);
                        kLineEntity.setCurTime(curTimeDates);
                        kLineEntity.setCreateTime(DateUtils.parseToDateTimeStr(new Date()));
                        System.err.println("OneMinKlineEntity--->" + kLineEntity.toString());
                    }
                    /**在内存中清除上一分钟的数据**/
                    FIVE_MIN_KLINE.remove(beforeHashKey);
                    /**开辟新的一分钟tikc内存**/
                    LinkedHashMap<String,KLineTickDto> afterOneMinMap=new LinkedHashMap<String,KLineTickDto>();
                    afterOneMinMap.put(hashValue.getUpdateTime(),hashValue);
                    FIVE_MIN_KLINE.put(hashKey,afterOneMinMap);
                }
            }else{
                /**不是5的倍数 找到上一个5分钟的key**/
                int i=minute%5;
                String oldHashKey=subHashKey[0]+"-"+subHashKeyTime[0]+":"+(minute-i);
                LinkedHashMap<String,KLineTickDto> sonMap=FIVE_MIN_KLINE.get(oldHashKey);
                sonMap.put(hashValue.getUpdateTime(),hashValue);
                FIVE_MIN_KLINE.put(oldHashKey,sonMap);
            }
        }catch (Exception e){
            LOGGER.error("calculateFiveMinKLine....error-->"+e);
        }

    }

    /**
     * 计算一分钟K线
     * @param hashKey 10001441-11:55
     * @param hashValue tick
     */
    @Async("executorPool")
    public void calculateOneMinKLine(String hashKey,KLineTickDto hashValue){
        try {
            boolean hashKeyFalg=ONE_MIN_KLINE.containsKey(hashKey);
            if(hashKeyFalg){
                /**如果存在则继续往内存里放**/
                LinkedList<KLineTickDto> sonList=ONE_MIN_KLINE.get(hashKey);
                sonList.add( hashValue);
//                System.out.println("hashValue.getUpdateTime()-->"+hashValue.getUpdateTime()+"hashValue-->"+hashValue);
                ONE_MIN_KLINE.put(hashKey,sonList);
            }else{
                /**如果不存在
                 * 1、计算上一分钟的tick,并清空上一分钟的数据
                 * 2、开辟新的一分钟tick内存
                 */
                String [] subHashKey=hashKey.split("-");
                Date beforeOneMinDate=DateUtils.addMinute(DateUtils.convertStringToDate("HH:mm", subHashKey[1]), -1);
                String beforeOneMinStr=DateUtils.formatDate("HH:mm", beforeOneMinDate);
                String beforeHashKey=subHashKey[0]+"-"+beforeOneMinStr;
                LinkedList<KLineTickDto> beforeOneMinList=ONE_MIN_KLINE.get(beforeHashKey);
                if(beforeOneMinList!=null){
//                    Collection<KLineTickDto> collections=beforeOneMinMap.values();
                    List<KLineTickDto> values=beforeOneMinList;
                    KLineEntity kLineEntity=new KLineEntity();
                    KLineTickDto headTick=values.get(0);
                    KLineTickDto tailTick=values.get(values.size()-1);
                    /**code**/
                    kLineEntity.setCode(subHashKey[0]);
                    /**开**/
                    kLineEntity.setOpen(Double.valueOf(headTick.getLastPrice()));
                    /**收**/
                    kLineEntity.setClose(Double.valueOf(tailTick.getLastPrice()));
                    /**成交量**/
                    Integer volum=Integer.valueOf(tailTick.getVolume())-Integer.valueOf(headTick.getVolume());
                    kLineEntity.setVolume(volum );
                    /**成交额**/
                    Double tradeAmt=Double.valueOf(tailTick.getTurnover())-Double.valueOf(headTick.getTurnover());
                    kLineEntity.setTradeAmt(tradeAmt);
                    /**持仓量**/
                    Double positionNum=Double.valueOf(tailTick.getOpenInterest())-Double.valueOf(headTick.getOpenInterest());
                    kLineEntity.setPositionNum(positionNum);
                    Double sumPrice=0.00;
                    for(KLineTickDto tick:values){
                        Double lastPrice=Double.valueOf(tick.getLastPrice());
                        /**高**/
                        if(kLineEntity.getHigh()==null || lastPrice>kLineEntity.getHigh()){
                            kLineEntity.setHigh(lastPrice);
                        }
                        /**低**/
                        if(kLineEntity.getLow()==null || lastPrice<kLineEntity.getLow()){
                            kLineEntity.setLow(lastPrice);
                        }
                        sumPrice+=lastPrice;
                    }
                    /**均价**/
                    Double avgPrice=new BigDecimal(sumPrice).divide(new BigDecimal(values.size()), 4, RoundingMode.HALF_UP).doubleValue();
                    kLineEntity.setAvgPrc(avgPrice);
                    /**mongodb+8小时 时区问题**/
                    String nowdate=DateUtils.convertDateToString(new Date())+headTick.getUpdateTime().substring(0, headTick.getUpdateTime().length()-3);
                    Date curTimeDates=DateUtils.addHour(DateUtils.convertStringToDate("yyyy-MM-ddHH:mm",nowdate),0);
                    kLineEntity.setCurTime(curTimeDates);
                    kLineEntity.setCreateTime(DateUtils.parseToDateTimeStr(new Date()));
                    System.err.println("OneMinKlineEntity--->" + kLineEntity.toString());
                    /**在内存中清除上一分钟的数据**/
                    ONE_MIN_KLINE.remove(beforeHashKey);
                }
                /**开辟新的一分钟tikc内存**/
                LinkedList<KLineTickDto> afterOneMinList=new LinkedList<KLineTickDto>();
                afterOneMinList.add(hashValue);
                ONE_MIN_KLINE.put(hashKey,afterOneMinList);
            }
        }catch (Exception e){
            LOGGER.error("calculateOneMinKLine....error-->",e);
        }

    }


    public static void main(String[] args) {
//        boolean flag=0%5==0;
//        System.err.println("flag-->" + flag);
//        int i=17%5;
//        System.err.println("i-->"+i);
//        //System.err.println("flag1-->"+flag1);
//        String instrumentMonth="201812";
//        String XDMonth="201812N1";
//        int XDValue=Integer.valueOf(XDMonth.substring(XDMonth.length() - 1));
//        System.err.println("XDValue-------->"+XDValue);
//        instrumentMonth=instrumentMonth+"N"+(XDValue+1);
//        System.err.println("instrumentMonth--->"+"XR2018asdf".replace("XD","").replace("XR","").substring("2018asdf".length()-1));

        String date="2018-12-1314:28:33";
        System.err.println("substring-->"+date.substring(0,date.length()-3));

    }
}
